﻿namespace DotNetCommon
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Net.Sockets;

    /// <summary>
    /// 网络帮助类
    /// </summary>
    /// <remarks>
    /// 功能: 获取计算机全限定域名 <seealso cref="GetFQDN"/>、 获取有效的IP地址 <seealso cref="GetLocalIPAddress"/>、 获取所有的IP地址 <seealso cref="GetLocalIPAddresses()"/>
    /// </remarks>
    public static class NetworkHelper
    {
        /// <summary>
        /// 获取计算机全限定域名( <c>FQDN</c> ,<c>Fully Qualified Domain Name</c>) <see href="http://stackoverflow.com/questions/804700/how-to-find-fqdn-of-local-machine-in-c-net"/>
        /// </summary>
        /// <remarks>关于FQDN: <see href="https://baike.baidu.com/item/FQDN/5102541"/></remarks>
        /// <returns></returns>
        public static string GetFQDN()
        {
            var domainName = IPGlobalProperties.GetIPGlobalProperties().DomainName;
            var hostName = Dns.GetHostName();

            domainName = "." + domainName;
            if (!hostName.EndsWith(domainName, StringComparison.InvariantCultureIgnoreCase))
            {
                hostName += domainName;
            }

            return hostName;
        }

        /// <summary>
        /// 获取本机联网使用的IP地址
        /// </summary>
        /// <remarks>
        /// <see href="http://stackoverflow.com/a/27376368"/>
        /// </remarks>
        /// <returns></returns>
        public static IPAddress GetLocalIPAddress()
        {
            using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0);

            try
            {
                // can be any address
                socket.Connect("10.0.2.4", 65530);
                var endPoint = socket.LocalEndPoint as IPEndPoint;
                // ReSharper disable once PossibleNullReferenceException
                return IPAddress.Parse(endPoint.Address.ToString());
            }
            catch (SocketException)
            {
                return IPAddress.Parse("127.0.0.1");
            }
        }

        /// <summary>
        /// 获取本地所有的IP地址( 注意: 不包含IPv6)
        /// <see href="https://blog.stephencleary.com/2009/05/getting-local-ip-addresses.html"/>
        /// </summary>
        public static IDictionary<IPAddress, string> GetLocalIPAddresses()
        {
            // Get a list of all network interfaces (usually one per network card, dial-up, and VPN connection)
            var nics = NetworkInterface.GetAllNetworkInterfaces();

            var result = new Dictionary<IPAddress, string>();
            foreach (var nic in nics)
            {
                foreach (var item in GetLocalIPAddresses(nic))
                {
                    result.Add(item, nic.Name);
                }
            }
            return result;
        }

        internal static IEnumerable<IPAddress> GetLocalIPAddresses(NetworkInterface nic)
        {
            // Read the IP configuration for each network
            var properties = nic.GetIPProperties();

            // Each network interface may have multiple IP addresses
            foreach (var address in properties.UnicastAddresses)
            {
                // We're only interested in IPv4 addresses for now
                if (address.Address.AddressFamily != AddressFamily.InterNetwork) { continue; }

                // Ignore loopback addresses (e.g., 127.0.0.1)
                if (IPAddress.IsLoopback(address.Address)) { continue; }

                yield return address.Address;
            }
        }
    }
}